package vn.mahjonggame.game.request;

import java.util.Collections;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.Logger;

import vn.mahjonggame.game.Mahjong;
import vn.mahjonggame.game.MahjongExtension;
import vn.mahjonggame.metadata.GameActionType;
import vn.mahjonggame.metadata.Player;
import vn.mahjonggame.metadata.MObject;
import vn.mahjonggame.metadata.Response;
import vn.mahjonggame.metadata.RoomVarName;
import vn.mahjonggame.metadata.Tile;
import vn.mahjonggame.metadata.TileSet;
import vn.mahjonggame.platform.PlatformConfig;
import vn.mahjonggame.util.Common;

import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.entities.variables.RoomVariable;
import com.smartfoxserver.v2.entities.variables.SFSRoomVariable;
import com.smartfoxserver.v2.extensions.BaseClientRequestHandler;
import com.smartfoxserver.v2.extensions.ExtensionLogLevel;

public class CallPonHandler extends BaseClientRequestHandler {	
	@Override
	public void handleClientRequest(final User user, ISFSObject params) {
		final MahjongExtension ext = (MahjongExtension) getParentExtension();
		callPon(ext, user, params);
	}
	
	public void callPon(final MahjongExtension ext, final User user, ISFSObject params){		
		setParentExtension(ext);
		Mahjong mahjong = ext.getMahjong();
		List<User> users = user.getLastJoinedRoom().getUserList();
		Room room = ext.getGameRoom();
		Logger logger = mahjong.getLogger();
		
		int tileId = params.getInt(MObject.tile.toString());		
		int bonusTime = params.getInt(MObject.bonusTime.toString());
		
		Player thrownPlayer = mahjong.getThrownPlayer();
		Player playerInTurn = mahjong.getPlayerInTurn();
		
		final Player player = mahjong.getPlayerById(user.getId());
		player.cancelTimer();
		
				
		/*
		 * Check if another player can call RON/OPENKAN
		 */
		if(mahjong.getCanCallOpenKanPlayer() != null){
						
			mahjong.setCallingPonPlayer(player);
			
			Map playerCache = player.getCache();
			playerCache.put(MObject.tile.toString(), tileId);
			playerCache.put(MObject.bonusTime.toString(), bonusTime);
			
			send(GameActionType.waitting.toString(), new SFSObject(), user);
			
			logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "Wait for another RON/KAN..."));
			return;
		}
		
		List<Tile> playerRightTiles = player.getRightTiles();
		List<Tile> playerLeftTiles = player.getLeftTiles();
		
		/*
		 * Move the tile which is thrown by the previous player to the right tiles of the current player
		 */
		Tile tile = thrownPlayer.getJustThrownTile();		
		
		playerRightTiles.add(tile);
		
		int thrownTileId = tile.getId();
		
		if(thrownTileId != tileId){
			String msg = "PON tile is " + tile.getId() + ", but you call " + tileId;			
			logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), msg));
			return;
		}
		
		/*
		 * Add the PON SET to the right hand and remove the correspond tile on the left hand 
		 */
		playerLeftTiles.removeAll(Collections.singleton(tile));
		playerRightTiles.addAll(Arrays.asList(tile, tile));			
		
		/*
		 * The tile of player is become public
		 */
		player.setPublic(true);
		
		/*
		 * Response to all clients
		 */	
				
		Response.Builder response = new Response.Builder();
		response.turn(player.getPlayerPosition())
				.turnTime(player.getTurnTime()/1000)
				.bonusTime(player.getBonusTime()/1000);
				
		Response.Builder object = new Response.Builder();
		object.losePos(thrownPlayer.getPlayerPosition())
				.winPos(player.getPlayerPosition())
				.loseTile(tile.getId())
				.winTile(Arrays.asList(thrownTileId, thrownTileId));
		
		response.PON(object.build().getSFSObject());		
		
		/*
		 * Send skip for the waiting player
		 */
		Player callingChiPlayer = mahjong.getCallingChiPlayer();
		if(callingChiPlayer != null){
			
			mahjong.setCallingChiPlayer(null);			
			
			final User tmpUser = mahjong.getUserByPlayerId(callingChiPlayer.getPlayerId(), users);
			
			Response.Builder skipResponse = new Response.Builder();
			skipResponse.type(TileSet.CHI.toString())
						.isConflict(false);
			
			SkipHandler skipHandler = new SkipHandler();
			skipHandler.skip(ext, tmpUser, skipResponse.build().getSFSObject(), false);
			
			logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "Send skip cmd for :" + callingChiPlayer.toString()));					
		}
		
		send(GameActionType.callPon.toString(), response.build().getSFSObject(), users);			
		
		ext.addAction(user, GameActionType.callPon.toString());
		
		player.setHasPicked(true);
		player.setHasThrown(false);
		
		
		player.updateBonusTime();
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "Bonus time from client: " + bonusTime * 1000));			
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "Bonus time from server: " + player.getBonusTime()));
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "startTime: " + player.getStartTime()));
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "leftTime: " + (player.getEndTime() - player.getStartTime())));
				
		mahjong.setPlayerInTurn(player);
		mahjong.resetTileSet();
		
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "player is " + player.toString()));
		
		mahjong.setCallingPonPlayer(null);		
		
		logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "tile :" + tile.toString()));
		
		if(player.isDisconnect() || Boolean.valueOf(room.getVariable(RoomVarName.is_auto.toString()).getStringValue())){
			/*
			 * Wait 5 second. If player does not thrown the tile, auto thrown the tile
			 */		
					
			final Response.Builder nextParams = new Response.Builder();			
			int size = player.getLeftTiles().size();
			tile = player.getLeftTiles().get(size - 1);
			nextParams.tile(tile.getId());			
			
			int delay = player.getTurnTime() + player.getBonusTime();	
			/*
			 * Only wait 1 second if the player is disconnected
			 */
			if(player.isDisconnect()){
				delay = 1000;
			}
			logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "isDisconnect: " + player.isDisconnect()));			
			logger.info(mahjong.log(room, player, GameActionType.callPon.toString(), "Calling throw handler: " + delay));
			Timer timer = player.getTimer();
			timer.schedule(new TimerTask() {
				  @Override
				  public void run() {
					  if(!player.isHasThrown()){
						  ThrowTileHandler throwTileHandler = new ThrowTileHandler();					  
						  throwTileHandler.throwTile(ext, user, nextParams.build().getSFSObject(), true, false);
					  }								
				  }
			}, delay);
		}
	}
}
